]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
grabHelper: Introduce a stack of grab helpers
authorJasper St. Pierre <jstpierre@mecheye.net>
Sat, 17 Aug 2013 00:11:36 +0000 (20:11 -0400)
committerJasper St. Pierre <jstpierre@mecheye.net>
Mon, 19 Aug 2013 13:35:09 +0000 (09:35 -0400)
GrabHelpers use a 'captured-event' to steal events and emulate
modality or grab-like semantics. There can be issues when you try to
use multiple GrabHelpers stacked on each other. As Clutter follows
the DOM-like semantics of "first come, first serve", when a second
GrabHelper connects to 'captured-event', its callback will only be
processed *after* the first GrabHelper's callback is called.

This breaks the expectation of narrowing modality where new modals
take priority over the old ones.

Solving this globally in a cleaner manner would require a rewrite of
pushModal/GrabHelper. As a stopgap fix for now, use one shared
'captured-event' handler between all GrabHelper instances, and
delegate to the individual GrabHelpers.

https://bugzilla.gnome.org/show_bug.cgi?id=699272

js/ui/grabHelper.js

index 296ce46f79fde8bf4637bbb014126b5efdf8a439..b022d1d6bd0aa956bdc2e3040f6168ccca5ccf01 100644 (file)
@@ -10,6 +10,31 @@ const St = imports.gi.St;
 const Main = imports.ui.main;
 const Params = imports.misc.params;
 
+let _capturedEventId = 0;
+let _grabHelperStack = [];
+function _onCapturedEvent(actor, event) {
+    let grabHelper = _grabHelperStack[_grabHelperStack.length - 1];
+    return grabHelper.onCapturedEvent(event);
+}
+
+function _pushGrabHelper(grabHelper) {
+    _grabHelperStack.push(grabHelper);
+
+    if (_capturedEventId == 0)
+        _capturedEventId = global.stage.connect('captured-event', _onCapturedEvent);
+}
+
+function _popGrabHelper(grabHelper) {
+    let poppedHelper = _grabHelperStack.pop();
+    if (poppedHelper != grabHelper)
+        throw new Error("incorrect grab helper pop");
+
+    if (_grabHelperStack.length == 0) {
+        global.stage.disconnect(_capturedEventId);
+        _capturedEventId = 0;
+    }
+}
+
 // GrabHelper:
 // @owner: the actor that owns the GrabHelper
 // @params: optional parameters to pass to Main.pushModal()
@@ -31,7 +56,6 @@ const GrabHelper = new Lang.Class({
         this._grabStack = [];
 
         this._actors = [];
-        this._capturedEventId = 0;
         this._ignoreRelease = false;
 
         this._modalCount = 0;
@@ -177,7 +201,7 @@ const GrabHelper = new Lang.Class({
             if (!Main.pushModal(this._owner, this._modalParams))
                 return false;
 
-            this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
+            _pushGrabHelper(this);
         }
 
         this._modalCount++;
@@ -189,8 +213,7 @@ const GrabHelper = new Lang.Class({
         if (this._modalCount > 0)
             return;
 
-        global.stage.disconnect(this._capturedEventId);
-        this._capturedEventId = 0;
+        _popGrabHelper(this);
 
         this._ignoreRelease = false;
 
@@ -251,7 +274,7 @@ const GrabHelper = new Lang.Class({
         }
     },
 
-    _onCapturedEvent: function(actor, event) {
+    onCapturedEvent: function(event) {
         let type = event.type();
 
         if (type == Clutter.EventType.KEY_PRESS &&